package com.jee.ssm.common.earthMagnet;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.setting.dialect.Props;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jee.ssm.common.socket.SocketMap;
import com.jee.ssm.common.socket.ZWSUtil;
import com.jee.ssm.common.utils.UUIDFactory;
import com.jee.ssm.model.Berth;
import com.jee.ssm.model.Handheld;
import com.jee.ssm.model.MagnetManager;
import com.jee.ssm.modules.handheld.services.HandheldService;
import com.jee.ssm.modules.posUser.services.PosUserService;
import com.jee.ssm.modules.posuserBerth.services.PosuserBerthService;
import org.apache.log4j.Logger;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.socket.TextMessage;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.*;

public class SocketHandle implements Runnable {

    //@Autowired
    //private AmqpTemplate amqpTemplate;

    private Logger logger = Logger.getLogger(SocketHandle.class);

    private Socket socket;
    private InputStream is;
    private OutputStream os;
    private boolean isConnected = false; //是否正在连接
    //private boolean firstConnected = false;//是否第一次连接
    //private boolean online = false; //是否在线
    //private boolean handled = false;
    //    private static List<String> list = Collections.synchronizedList(new ArrayList<>());
    private final List<byte[]> messageList = Collections.synchronizedList(new ArrayList<>());
    //private String socketCode;//设备ID号采用字符串方式，实际为WiFi模块的芯片ID号，这样我们公司出厂的产品就不必才重新制定新的ID号码，长度为8个字节，全部为字符串数据。
    //private String dataType;//数据类型 0x00 下发 0x01 上传
    //private String messageType;//

    public SocketHandle(Socket socket) {
        this.socket = socket;
        try {
            this.socket.setKeepAlive(true);
            this.socket.setSoTimeout(1000 * 60 * 60 * 2);
            this.is = socket.getInputStream();
            this.os = socket.getOutputStream();
            this.isConnected = true;
            //this.firstConnected = true;
        } catch (IOException e) {
            //e.printStackTrace();
        }
    }

    private void removeSocket() {
        this.isConnected = false;
        try {
            if (this.is != null)
                this.is.close();
            if (this.os != null)
                this.os.close();
            if (this.socket != null) {
                this.socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void run() {
        new Thread(() -> {
            try {
                while (this.isConnected) {
                    byte[] b = new byte[256];
                    int len = 0;
                    len = this.is.read(b);
                    //this.logger.info("信息长度：" + len);
                    Thread.sleep(1000);
                    if (len > 0) {
                        messageList.add(b);
                        //this.logger.info("已载任务数：" + this.messageList.size());
                    }
                }
            } catch (IOException e) {
                logger.info("传输：" + this.messageList.size() + "现异常！");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                removeSocket();
            }
        }).start();

        new Thread(() -> {
            try {
                while (this.isConnected) {
                    if (messageList.size() > 0) {
//                        handleArray(messageList.get(0));
                        handle(messageList.get(0));
                        //logger.info("当前剩余任务：" + messageList.size());
                    }
                    Thread.sleep(1000);
                }
            } catch (Exception e) {
                logger.info("任务：" + messageList.size() + "出异常！");
            } finally {
                removeSocket();
            }


        }).start();

    }

    private void handle(byte[] b) {
        messageList.remove(0);
        if (b != null && b.length != 0) {
            //命令0x00 管理器向平台注册数据
            //命令0x01 管理器上发检测器心跳数据
            //命令0x02 管理器上发检测器车位变化数据
            //命令0x03 管理器上发自身心跳数据
            //命令0x80 平台下发注册指令应答
            //命令0x83 管理器心跳应答
            String command = Utils.bytes2HexStr(subByte(b, 3, 1));

            ApplicationContext act = ApplicationContextRegister.getApplicationContext();

            String comStr = "";
            if("00".equals(command)){
                comStr = "管理器向平台注册";
            }
            if("01".equals(command)){
                comStr = "检测器心跳";
            }
            if("02".equals(command)){
                comStr = "检测器车位变化";
            }
            if("03".equals(command)){
                comStr = "管理器自身心跳";
            }
            logger.info("===========================================");
            logger.info("地磁管理器，收到命令："+comStr);

            if ("00".equals(command)) {            //命令0x00 管理器向平台注册数据

                byte checkSum = 0;

                for (int i = 0; i < 79; i++) {
                    int q = b[i] & 0xff;

                    checkSum = (byte) (checkSum + q);

                }

                String checkSum1 = Utils.bytes2HexStr(subByte(b, 79, 1));
                Integer aa = Integer.parseInt(checkSum1, 16);
                logger.info("地磁管理器注册，校验1："+String.valueOf(checkSum)+"  校验2："+aa.toString());
                if (String.valueOf(checkSum).equals(aa.toString())) {//判断校验和
                    logger.info("地磁管理器注册，校验成功。");
                    //管理器ID
                    byte[] manIdByte = subByte(b, 4, 10);
                    String manId = new String(manIdByte);
                    //检测器ID
                    byte[] manIdByte2 = subByte(b, 14, 10);
                    String jId = new String(manIdByte2);
                    //卡号信息（暂无意义）
                    byte[] manIdByte3 = subByte(b, 24, 20);
                    String CardId = new String(manIdByte3);

                    String ip = String.valueOf(b[44] & 0xff) + "." +
                            String.valueOf(b[45] & 0xff) + "." +
                            String.valueOf(b[46] & 0xff) + "." +
                            String.valueOf(b[47] & 0xff); //本地IP（地磁管理器ip）

                    String ipMask = String.valueOf(b[48] & 0xff) + "." +
                            String.valueOf(b[49] & 0xff) + "." +
                            String.valueOf(b[50] & 0xff) + "." +
                            String.valueOf(b[51] & 0xff); //子网掩码

                    String gateWay = String.valueOf(b[52] & 0xff) + "." +
                            String.valueOf(b[53] & 0xff) + "." +
                            String.valueOf(b[54] & 0xff) + "." +
                            String.valueOf(b[55] & 0xff); //网关

                    String disIp = String.valueOf(b[56] & 0xff) + "." +
                            String.valueOf(b[57] & 0xff) + "." +
                            String.valueOf(b[58] & 0xff) + "." +
                            String.valueOf(b[59] & 0xff); //目标IP（服务器ip）

//                    String macId = String.valueOf(b[60] & 0xff) + ":" +
//                            String.valueOf(b[61] & 0xff) + ":" +
//                            String.valueOf(b[62] & 0xff) + ":" +
//                            String.valueOf(b[63] & 0xff) + ":" +
//                            String.valueOf(b[64] & 0xff) + ":" +
//                            String.valueOf(b[65] & 0xff); //MAC地址

                    String macId = Utils.byteToHex(b[60]) + ":" +
                            Utils.byteToHex(b[61]) + ":" +
                            Utils.byteToHex(b[62]) + ":" +
                            Utils.byteToHex(b[63]) + ":" +
                            Utils.byteToHex(b[64]) + ":" +
                            Utils.byteToHex(b[65]);

                    String port = String.valueOf(b[66] & 0xff) + String.valueOf(b[67] & 0xff);//端口号
                    String des = String.valueOf(b[68] & 0xff);//预留参数
                    String year = String.valueOf(b[72] & 0xff) + String.valueOf(b[73] & 0xff);
                    String month = String.valueOf(b[74] & 0xff);
                    String day = String.valueOf(b[75] & 0xff);
                    String version = String.valueOf(b[76] & 0xff) + "." + String.valueOf(b[77] & 0xff);
                    String res = String.valueOf(b[78] & 0xff);

                    MagnetManager magnetManager = new MagnetManager(UUIDFactory.getStringId(), manId, macId, ip, gateWay, new Date(), new Date(), ipMask);

//                    magnetManager.setCode(manId);
//                    magnetManager.setIp(ip);
//                    magnetManager.setLastTime(new Date());
//                    magnetManager.setCreateTime(new Date());
//                    magnetManager.setGateWay(gateWay);
//                    magnetManager.setIpMask(ipMask);
//                    magnetManager.setId(UUIDFactory.getStringId());
//
//                  注冊地磁管理器
                    logger.info("地磁管理器注册，mac地址：" + macId);
                    Props props = new Props("config/project.properties");
                    String serverUrl = props.getProperty("server.url"); //停车服务的地址
                    String method = props.getProperty("tc.saveParkMagnet");
                    String jsonMagnet = JSONObject.toJSONString(magnetManager);
                    HttpRequest.post(serverUrl + method).form("jsonMagnet", jsonMagnet).execute();


                } else {
                    logger.info("地磁管理器注册，校验失败，不予注册。");
                }
            }
            //命令0x02 管理器上发检测器车位变化数据
            // 命令0x01 管理器上发检测器心跳数据
            if ("02".equals(command) || "01".equals(command)) {

                byte checkSum = 0;

                for (int i = 0; i < 47; i++) {
                    int q = b[i] & 0xff;

                    checkSum = (byte) (checkSum + q);

                }

                String checkSum2 = Utils.bytes2HexStr(subByte(b, 47, 1));
                Integer bb = Integer.parseInt(checkSum2, 16);
                logger.info("检测器，16进制：" + checkSum2);
                logger.info("检测器，Byte ：" + checkSum);
                logger.info("检测器，10进制：" + bb.toString());

                if (String.valueOf(checkSum).equals(bb.toString())) {//判断校验和
                    //管理器ID
                    byte[] manIdByte = subByte(b, 4, 10);
                    String manId = new String(manIdByte);
                    logger.info("管理器，ID：" + manId);
                    //检测器ID
                    byte[] manIdByte2 = subByte(b, 14, 10);
                    String jId = new String(manIdByte2);
                    logger.info("检测器，ID：" + jId);
                    //bit0..1 1-无车，2-有车
                    //bit2..3 1 电池状态 1-正常 2-欠压
                    //bit4 设备状态 1-正常 0-故障
                    //bit5..6 剩余电量 0-100% 1-%75% 2-50% 3-25%
                    //bit7 磁场警告 0-正常 1-告警
                    //String status =  Utils.bytes2HexStr(subByte(b, 46, 1));
                    String status = Integer.toBinaryString(b[46]);
                    //logger.info("检测器，status：" + status);
                    if (status.length() < 8) {
                        int w = 8 - status.length();
                        for (int i = 0; i < w; i++) {
                            status = 0 + status;
                        }
                    }

                    String statusa = status.substring(6, 8);
                    String statusb = status.substring(4, 6);
                    String statusc = status.substring(3, 4);
                    String statusd = status.substring(1, 3);
                    String statuse = status.substring(0, 1);

                    try {
//                        Berth berth = new Berth();

                        Integer berthStatus = 0;
                        Integer powerStatus = 0;
                        Integer magnetStatus = 0;
                        Integer power = 0;
                        Integer magnetAlarm = 0;

                        //车位状态
                        if (statusa.equals("01")) {//1：无车
//                            berth.setBerthStatus(1);
                            berthStatus = 1;
                        } else if (statusa.equals("10")) {//2：有车
//                            berth.setBerthStatus(2);
                            berthStatus = 2;
                        }
                        //电池状态
                        if (statusb.equals("01")) {//1：正常
//                            berth.setPowerStatus(1);
                            powerStatus = 1;
                        } else if (statusb.equals("10")) {//2：欠压
//                            berth.setPowerStatus(2);
                            powerStatus = 2;
                        }
                        //设备状态
                        if (statusc.equals("0")) {//0：故障
//                            berth.setMagnetStatus(0);
                            magnetStatus = 0;
                        } else if (statusc.equals("1")) {//1：正常
//                            berth.setMagnetStatus(1);
                            magnetStatus = 1;
                        }
                        //剩余电量
                        if (statusd.equals("00")) {//0：100%
//                            berth.setPower(0);
                            power = 0;
                        } else if (statusd.equals("01")) {//1：75%
//                            berth.setPower(1);
                            power = 1;
                        } else if (statusd.equals("10")) {//2：50%
//                            berth.setPower(2);
                            power = 2;
                        } else if (statusd.equals("11")) {//3：25%
//                            berth.setPower(3);
                            power = 3;
                        }
                        //磁场告警
                        if (statuse.equals("0")) {//0：正常
//                            berth.setMagnetAlarm(0);
                            magnetAlarm = 0;
                        } else if (statuse.equals("1")) {//1：告警
//                            berth.setMagnetAlarm(1);
                            magnetAlarm = 1;
                        }

                        logger.info("检测器，状态 - 有无车：" + berthStatus);
                        //logger.info("检测器，状态 - 电池状态：" + powerStatus);
                        //logger.info("检测器，状态 - 设备状态：" + magnetStatus);
                        //logger.info("检测器，状态 - 电量：" + power);
                        //logger.info("检测器，状态 - 磁场：" + magnetAlarm);

                        Berth berth = new Berth(jId.trim(), berthStatus, powerStatus, magnetStatus, power, magnetAlarm);


                        //修改服务器上车位状态
                        Props props = new Props("config/project.properties");
                        String serverUrl = props.getProperty("server.url"); //停车服务的地址
                        String method = props.getProperty("tc.updateByMagnetCode");
                        String jsonBerth = JSONObject.toJSONString(berth);
                        HttpRequest.post(serverUrl + method).form("jsonBerth", jsonBerth).execute();

                        //获取修改完状态的车位信息
                        String method1 = props.getProperty("tc.selectByMagnet");
                        String result = HttpRequest.get(serverUrl + method1).form("magnetCode", jId.trim()).execute().body();
                        Berth berth1 = JSON.parseObject(result, Berth.class);


                        //根据车位查询手持机用户
                        PosuserBerthService posuserBerthService = act.getBean(PosuserBerthService.class);
                        PosUserService posUserService = act.getBean(PosUserService.class);
                        String userId = posuserBerthService.selectByBerthId(berth1.getId()).getUserId();

                        HandheldService handheldService = act.getBean(HandheldService.class);
                        Handheld handheld = handheldService.selectByUserId(userId);
                        if (handheld != null && handheld.getPosNumber()!=null) {
                            String sbCode = handheld.getPosNumber();

                            //向手持机发送消息
                            Map<String, Object> map = new HashMap<>();
                            map.put("type", "1");
                            map.put("berthCode", berth1.getBerthCode());
//                            ZWSUtil.wssMap.get(sbCode).getWebSocketSession().sendMessage((new TextMessage(JSON.toJSONString(map))));
                            logger.info("发送给手持机：" + sbCode + " ==> " + JSON.toJSONString(map));
                            posUserService.send(sbCode,JSON.toJSONString(map));
                        }else{
                            logger.info("发送给手持机：没有找到用户对应的手持机，userId：" + userId);
                        }


                    } catch (Exception e) {
                        e.printStackTrace();
                    }


                } else {
                    logger.info("地磁管理，校验失败。");
                }
            }
            if ("03".equals(command)) {            //命令0x03 管理器上发自身心跳数据
                String manId = Utils.bytes2HexStr(subByte(b, 4, 10));
                String jId = Utils.bytes2HexStr(subByte(b, 14, 10));//检测器ID
            }
            reply(b,command);
        }
    }


    /**
     * 截取byte数组   不改变原数组
     *
     * @param b      原数组
     * @param off    偏差值（索引）
     * @param length 长度
     * @return 截取后的数组
     */
    public byte[] subByte(byte[] b, int off, int length) {
        byte[] b1 = new byte[length];
        System.arraycopy(b, off, b1, 0, length);
        return b1;
    }

    //命令0x80 平台下发注册指令应答
    //命令0x83 管理器心跳应答
    public void reply(byte[] data,String s){
        byte[] reply = new byte[28];
        byte head = (byte) 0xA7;
        byte hea2 = (byte) 0xA8;
        byte  dlong = (byte) 0x1C;
        byte mingl = (byte) 0x0;
        byte[] mng = subByte(data, 4, 10);
        byte summng = (byte) 0x0;
        for (byte b : mng){
            summng = (byte) (summng + b);
        }
        //检测器ID
        byte[] sen = subByte(data, 14, 10);
        byte sumsen = (byte) 0x0;
        for (byte b : sen){
            sumsen = (byte) (sumsen + b);
        }
        byte result = (byte) 0x1;
        byte result1 = (byte) 0x0;
        byte result2 = (byte) 0x0;
        if ("00".equals(s)){
            mingl = (byte) 0x80;
        }else if ("03".equals(s)){
            mingl = (byte) 0x83;
        }
        byte checksum = (byte) (head +hea2 + dlong + mingl +summng + sumsen + result + result1 +result2);
        reply[0] = head;
        reply[1] = hea2;
        reply[2] = dlong;
        reply[3] = mingl;
        for (int i = 4 ; i< 14 ; i++){
            reply[i] = mng[i-4];
        }
        for (int i = 14 ; i< 24 ; i++){
            reply[i] = mng[i-14];
        }
        reply[24] = result;
        reply[25] = result1;
        reply[26] = result2;
        reply[27] = checksum;
        try {
            if ("00".equals(s)){
                os.write(reply);
                os.flush();
            }else if ("03".equals(s)){
                os.write(reply);
                os.flush();
            }
            //logger.info("地磁管理，回复协议。" + s);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

